#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h> 
#include <stdint.h>
#include "util.h"
#include <inttypes.h>

/********************************************************
  这个是AS进程。在这个Kerberos模拟程序里，假设AS只知道唯一
  的用户Bob，并且Bob的Master Key为0x6162636465666768，即
  可见字符串"abcdefgh"的ASCII。
*********************************************************/
#define CLIENT_ID "Bob"
#define K_CLIENT 0x6162636465666768
#define K_TGS 0x3031323334353637

int check_client_id(const char *cid) {
    return strcmp(CLIENT_ID, cid) == 0;
}

int main() {
    srand(time(NULL));
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr, client_addr;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, 0, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(11111); 

    int res = bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
    if (res != 0) {
        printf("errno %d: %s\n", errno, strerror(errno));
        return 1;
    }

    listen(listenfd, 10); 

    int client_len = sizeof(struct sockaddr_in);
    char client_ip[20];
    char client_ip_port[30];
    printf("Authentication server started!\n");
    while (1) {
        printf("Listening...\n");
        connfd = accept(listenfd, (struct sockaddr*)&client_addr, (socklen_t*)&client_len); 
        inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip));
        sprintf(client_ip_port, "%s:%d", client_ip, ntohs(client_addr.sin_port));
        printf("Accepted %s\n", client_ip_port);

        /* 先接收明文Client ID，并检查数据库是否存在此用户 */
        multi_msg plain1 = new_multi_msg();
        mm_sock_read(&plain1, connfd);
        const char *cid = (char*)plain1.msgs[0].data;
        multi_msg message_ab = new_multi_msg();
        
        /* 返回AB两则消息 */
        if (check_client_id(cid)) { // client id exists
            uint64_t k_client_tgs = rand_uint64();
            printf("Generate a new k_client_tgs: %016" PRIx64 "\n", k_client_tgs);
            multi_msg message_a = new_multi_msg();
            mm_build(&message_a, "k", k_client_tgs);
            octet_string os_a = new_octet_string();
            mm_dumps_encrypt(&os_a, &message_a, K_CLIENT);
            mm_free(&message_a);

            multi_msg message_b = new_multi_msg();
            mm_build(&message_b, "ssk", cid, client_ip_port, k_client_tgs);
            octet_string os_b = new_octet_string();
            mm_dumps_encrypt(&os_b, &message_b, K_TGS);
            mm_free(&message_b);

            mm_build(&message_ab, "soo", "success", &os_a, &os_b);
            os_free(&os_a);
            os_free(&os_b);
        }
        else {  // not exists
            mm_build(&message_ab, "s", "fail");
        }
        mm_sock_write(connfd, &message_ab);
        mm_free(&message_ab);
        

        close(connfd);
        sleep(1);
     }
}
